﻿using Autofac;
using Autofac.Extensions.DependencyInjection;
using IoC.Interfaces;
using IoC.Services;
using Microsoft.Extensions.DependencyInjection;

namespace IoC
{
    public class Program
    {
        public static void Main(string[] args)
        {
            #region 内置IoC容器

            {
                // 创建内置的IoC容器
                IServiceCollection services = new ServiceCollection();

                // 类型注入，每次会创建新的实例（使用构造函数注入）
                services.AddTransient<IMicroPhone, MicroPhone>();

                // 使用IoC容器创建对象实例
                ServiceProvider serviceProvider = services.BuildServiceProvider();

                for (int i = 0; i < 3; i++)
                {
                    IMicroPhone microPhone = serviceProvider.GetService<IMicroPhone>();
                }
            }

            {
                // 创建内置的IoC容器
                IServiceCollection services = new ServiceCollection();

                // 构造函数注入
                services.AddTransient<IMicroPhone, MicroPhone>();
                services.AddTransient<IPower, Power>();
                services.AddTransient<IHeadPhone, HeadPhone>();
                services.AddTransient<ICellPhone, ApplePhone>();

                ServiceProvider serviceProvider = services.BuildServiceProvider();

                ICellPhone? cellPhone = serviceProvider.GetService<ICellPhone>();
            }

            // 属性注入.Net Core/7/8均不支持

            {
                // 方法注入：通过 FromServices 特性标记需要注入的方法参数
                // 具体示例参见WebApi项目的IocController中相关方法
            }

            {
                // IoC容器的生命周期
                {
                    // 1. 瞬时生命周期：每一次获取的实例都是一个全新创建的实例，使用 [Try]AddTransient() 方法注册
                    IServiceCollection services = new ServiceCollection();
                    services.AddTransient<IMicroPhone, MicroPhone>();

                    ServiceProvider serviceProvider = services.BuildServiceProvider();

                    IMicroPhone? microPhone1 = serviceProvider.GetService<IMicroPhone>();
                    IMicroPhone? microPhone2 = serviceProvider.GetService<IMicroPhone>();
                    IMicroPhone? microPhone3 = serviceProvider.GetService<IMicroPhone>();
                    IMicroPhone? microPhone4 = serviceProvider.GetService<IMicroPhone>();

                    Console.WriteLine(Object.ReferenceEquals(microPhone1, microPhone2));
                    Console.WriteLine(Object.ReferenceEquals(microPhone2, microPhone3));
                    Console.WriteLine(Object.ReferenceEquals(microPhone3, microPhone4));
                    Console.WriteLine(Object.ReferenceEquals(microPhone1, microPhone4));
                }

                {
                    // 2. 单例生命周期：每一次获取的实例都是同一个实例，使用 [Try]AddSingleton() 方法注册
                    IServiceCollection services = new ServiceCollection();
                    services.AddSingleton<IMicroPhone, MicroPhone>();

                    ServiceProvider serviceProvider = services.BuildServiceProvider();

                    IMicroPhone? microPhone1 = serviceProvider.GetService<IMicroPhone>();
                    IMicroPhone? microPhone2 = serviceProvider.GetService<IMicroPhone>();
                    IMicroPhone? microPhone3 = serviceProvider.GetService<IMicroPhone>();
                    IMicroPhone? microPhone4 = serviceProvider.GetService<IMicroPhone>();

                    Console.WriteLine(Object.ReferenceEquals(microPhone1, microPhone2));
                    Console.WriteLine(Object.ReferenceEquals(microPhone2, microPhone3));
                    Console.WriteLine(Object.ReferenceEquals(microPhone3, microPhone4));
                    Console.WriteLine(Object.ReferenceEquals(microPhone1, microPhone4));
                }

                {
                    // 3. 作用域生命周期：从同一个 ServiceProvider 获取回来的实例是同一个，不同 ServiceProvider 获取回的实例不是同一个
                    IServiceCollection services = new ServiceCollection();
                    services.AddScoped<IMicroPhone, MicroPhone>();

                    ServiceProvider serviceProvider1 = services.BuildServiceProvider();

                    IMicroPhone? microPhone1 = serviceProvider1.GetService<IMicroPhone>();
                    IMicroPhone? microPhone2 = serviceProvider1.GetService<IMicroPhone>();

                    ServiceProvider serviceProvider2 = services.BuildServiceProvider();

                    IMicroPhone? microPhone3 = serviceProvider2.GetService<IMicroPhone>();
                    IMicroPhone? microPhone4 = serviceProvider2.GetService<IMicroPhone>();

                    Console.WriteLine(Object.ReferenceEquals(microPhone1, microPhone2));
                    Console.WriteLine(Object.ReferenceEquals(microPhone2, microPhone3));
                    Console.WriteLine(Object.ReferenceEquals(microPhone3, microPhone4));
                    Console.WriteLine(Object.ReferenceEquals(microPhone1, microPhone4));
                }

                {
                    // 如何解决单抽象多实现问题

                    IServiceCollection services = new ServiceCollection();

                    services.AddTransient<IMicroPhone, MicroPhone>();
                    services.AddTransient<IMicroPhone, MicroPhoneNew>();

                    ServiceProvider serviceProvider = services.BuildServiceProvider();

                    // 默认情况下，获取单个实例会获取后最后注册的实现
                    IMicroPhone? microPhone1 = serviceProvider.GetService<IMicroPhone>();
                    IMicroPhone? microPhone2 = serviceProvider.GetService<IMicroPhone>();

                    // 可获取所有实现实例集合
                    IEnumerable<IMicroPhone>? microPhones = serviceProvider.GetService<IEnumerable<IMicroPhone>>();
                    Console.WriteLine(microPhones);

                    // 如果想获取前面注册的实例，.Net 8 下支持给注册的service加Key，在获取的时候也必须使用Key来获取
                    services.AddKeyedTransient<IMicroPhone, MicroPhone>("MP1");
                    services.AddKeyedTransient<IMicroPhone, MicroPhoneNew>("MP2");

                    ServiceProvider serviceProvider1 = services.BuildServiceProvider();

                    IMicroPhone? microPhone3 = serviceProvider1.GetKeyedService<IMicroPhone>("MP1");
                    IMicroPhone? microPhone4 = serviceProvider1.GetKeyedService<IMicroPhone>("MP2");
                }
            }

            #endregion 内置IoC容器

            #region 使用 Autofac

            {
                ServiceCollection services = new ServiceCollection();

                ContainerBuilder containerBuilder = new ContainerBuilder();

                containerBuilder.Populate(services);

                containerBuilder.RegisterType<MicroPhone>().As<IMicroPhone>();
                containerBuilder.RegisterType<MicroPhoneNew>().Keyed<IMicroPhone>("MP2");

                IContainer container = containerBuilder.Build();

                IServiceProvider serviceProvider = new AutofacServiceProvider(container);

                IMicroPhone? microPhone = serviceProvider.GetService<IMicroPhone>();

                IMicroPhone? microPhone2 = serviceProvider.GetKeyedService<IMicroPhone>("MP2");
            }

            #endregion 使用 Autofac
        }
    }
}